#include "../utils/pch.h"
#include "../utils/IniReader.h"
#include "../utils/PcapUtils.h"
#include "main.h"
#include "../utils/SafeQueueTemplate.h"
#include "../utils/SPMCQueueTemplate.h"
#include "../utils/my_efvicap.h"

#define USE_EFVI 1

#ifdef USE_EFVI
#include "../utils/Efvi.h"
#include "../utils/my_efvicap.h"

using UdpReceiver = EfviUdpReceiver;
using UdpSender = EfviUdpSender;
#else
#include "../utils/Socket.h"
using UdpReceiver = SocketUdpReceiver<>;
using UdpSender = SocketUdpSender;
#endif

#ifdef MY_COMPILE_TIME
extern const char* my_compile_time = MY_COMPILE_TIME;
#else
const char* my_compile_time = "Unknown";
#endif


// 全局共享配置
namespace Global {
    const std::string Version = "0.0.2";
    const std::string Date = "0.0.2";

    // 声明全局变量
    std::string globalString = ""; // 定义，声明在pch.h中
    int globalInt = 0;
    int g_exit = 0; // 退出标志
}

namespace ntp{
    // 定义全局变量
    std::string global_message = "Hello, World!";
    std::mutex global_mutex;

    // 共享的日志对象
    std::shared_ptr<spdlog::logger> my_nm_logger;



    // 共享队列1 = 普通队列
    std::queue<MarketData> data_queue1;
    std::queue<MarketData> data_queue2;
    SafeQueue<MarketData> queueLine1, queueLine2;
    constexpr uint32_t QUEUE_SIZE = 16; // 队列大小必须是2的幂次
    SPMCQueue<MarketData, 1024> queueL1, queueL2;



}

#define HOME_DIR "/tmp/tmp.FdUHWCPhyb/V2"

std::shared_ptr<spdlog::logger> spdlog_init() {
    // 初始化异步线程池
    spdlog::init_thread_pool(8192, 1);
    // 创建 sinks
    auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
    console_sink->set_level(spdlog::level::debug);

    auto file_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(
            "logs/app.log", 1024 * 1024 * 5, 3);
    file_sink->set_level(spdlog::level::info);

    // 创建异步日志器
    auto logger = std::make_shared<spdlog::async_logger>(
            "async_logger", spdlog::sinks_init_list{console_sink, file_sink},
            spdlog::thread_pool(), spdlog::async_overflow_policy::block);
    logger->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] [%s:%#] %v");
    spdlog::register_logger(logger);

    return logger;
}

void use_efvi(ntp::IniReader* iniCfg) {
    std::string device = iniCfg->ReadString("LINE_1", "device","");
    std::string sourceIP = iniCfg->ReadString("LINE_1", "sourceIP","");
    std::string destinationIP = iniCfg->ReadString("LINE_1", "destinationIP",""); // 目标ip = 组播ip
    std::string destinationPort = iniCfg->ReadString("LINE_1", "destinationPort",""); // 目标端口 = 组播端口
    std::string filterStr = iniCfg->ReadString("LINE_1", "filterStr",""); // 抓包过滤条件


    const char* interface = device.data();
    const char* local_ip = destinationIP.data();
    int local_port = std::stoi(destinationPort.data());
    const char* sub_ip = ""; // 子网掩码，可不填

    std::cout << "参数：interface=" << interface
    << ", local_ip=" << local_ip
    << ", destinationPort=" << local_port
    << ", sub_ip=" << sub_ip
    << std::endl;

    UdpReceiver receiver;
    if (!receiver.init(interface, local_ip, local_port, sub_ip)) {
        std::cout << receiver.getLastError() << std::endl;
        //return 1;
    }

    int cur = 0;
    int bad_cnt = 0;
    int miss_cnt = 0;
    int cnt = 0;
    while (1) {
        receiver.read([&](const uint8_t* data, uint32_t len, timespec ts) {
            cnt++;
            std::cout << cnt << "原始数据包: ts.tv_sec=" << ts.tv_sec << ":" << ts.tv_nsec << std::endl;
            // 输出原始数据包内容，以十六进制形式输出
            for (int i = 0; i < 20; i++) {
                printf("%02x ", data[i]);
                if ((i + 1) % 20 == 0) {
                    printf("\n");
                }
            }
            printf("\n");

            if (len != 201) {
                std::cout << "error len: " << len << std::endl;
                bad_cnt++;
                return;
            }
            while (data[0] != cur + '0') {
                miss_cnt++;
                std::cout << "miss: " << (char)(cur + '0') << std::endl;
                cur++;
                if (cur == 10) cur = 0;
            }
            for (int i = 0; i < 200; i++) {
                if (data[i] != data[0]) {
                    std::cout << "invalid data: " << data << std::endl;
                    bad_cnt++;
                    break;
                }
            }
            cur++;
            if (cur == 10) cur = 0;
        });

        sleep(3);
    }

}

void use_efvi2(std::string sectionId, ntp::IniReader* iniCfg, SafeQueue<MarketData>* data_queue) {
    main3(sectionId, iniCfg);

}

// 信号处理函数
extern "C" void my_signalHandler(int signal) {
    // 停止时开始统计
    std::cout << "停止信号处理函数" << std::endl;
    // 退出程序
    exit(0);
}
static void sigIntHander(int signalNum) {
    ntp::my_nm_logger->info("捕获到停止信号 {}", signalNum);
    Global::g_exit = 1;
}

void SignalProcess() {
    // 捕获到退出信号后，修改退出标记，执行退出动作
    signal(SIGINT, sigIntHander);
    signal(SIGKILL, sigIntHander);
    signal(SIGTERM, sigIntHander);
}

int main(int argc, char *argv[]) {
    std::string debug;
    if (argc > 1) {
        debug = argv[1]; // 默认没有debug, 加debug参数后有debug功能
    }
    using namespace ntp;
    // 将信号处理函数注册为处理 SIGINT 信号
    std::signal(SIGINT, my_signalHandler);

    // 初始化运行时日志
    //ntp::my_nm_logger = spdlog::basic_logger_mt("test_logger", "runingTimeLogger.txt"); // basic_logger 固定写法
    //spdlog::set_default_logger(my_nm_logger);
    //spdlog::flush_on(spdlog::level::info);
    //spdlog::get("test_logger")->info("LoggingTest::ctor");

    ntp::my_nm_logger = spdlog_init();
    // 使用日志器
    SPDLOG_LOGGER_INFO(my_nm_logger,"============================ 程序开始执行 ============================");
    //SPDLOG_LOGGER_INFO(my_nm_logger,"version: {},spdlog: {}", Global::Version, my_nm_logger->name());
    SPDLOG_LOGGER_INFO(my_nm_logger,"程序基本信息: version: {}, my_compile_time: {}, spdlog: {}", Global::Version, my_compile_time, my_nm_logger->name());


    // 获取启动时间
    auto aa = currTime();
    // 获取当前时间作为启动时间
    std::chrono::system_clock::time_point startTime = std::chrono::system_clock::now();
    // 获取当前工作路径
    char cwd[1024];
    if (getcwd(cwd, sizeof(cwd)) == NULL) {
        perror("getcwd");
        return 1;
    }


    // 初始化配置文件对象
    IniReader* iniCfg = new IniReader();
    std::string cwdStr(cwd);
    std::string cfgPathName = cwdStr + "/my_config.ini";
    //std::string cfgPathName = HOME_DIR"/my_config.ini";

    SPDLOG_LOGGER_INFO(my_nm_logger, "程序启动路径为：{} ,启动时间：{}", cwd, aa);
    SPDLOG_LOGGER_INFO(my_nm_logger, "读取的配置文件：{}", cfgPathName);

    if (!iniCfg->ReadConfig(cfgPathName)) {
        SPDLOG_LOGGER_INFO(my_nm_logger, "读取 ini 配置文件失败");
        exit;
    }
    else {
        SPDLOG_LOGGER_INFO(my_nm_logger, "读取 my_config.ini 配置文件成功");
    }

    // 初始化公共数据类
    ShareDataClzz* shareDataClzz = new ShareDataClzz(iniCfg);


    // pcap库测试
    PcapUtils pcapUtils(my_nm_logger, shareDataClzz);
    //PcapUtils pcapUtils;
    //pcapUtils.readPcapFile();
    //pcapUtils.readNetworkInterface();
    //pcapUtils.readNetworkIface();
    //pcapUtils.readNetworkIface4();


    // 读取两路行情，用同一个起点做对比
    auto readLambda = [](PcapUtils pcapUtils, std::shared_ptr<spdlog::logger> my_logger,
            IniReader* iniCfg, std::chrono::system_clock::time_point startTime, SafeQueue<MarketData>* data_queue1, SafeQueue<MarketData>* data_queue2) {
        SPDLOG_LOGGER_INFO(my_logger,"消费者线程 - 启动读行情线程");
        pcapUtils.readMsg(my_logger, iniCfg, data_queue1, data_queue2);
    };
    //std::thread task2(readLambda, pcapUtils, my_nm_logger, iniCfg, startTime, data_queue1);
    //std::thread task2(readLambda, pcapUtils, my_nm_logger, iniCfg, startTime, &queueLine1, &queueLine2);

    // 写行情1
    auto writeLambda1 = [](ntp::PcapUtils pcapUtils, std::shared_ptr<spdlog::logger> my_logger,
            IniReader* iniCfg, std::chrono::system_clock::time_point startTime, SafeQueue<MarketData>* data_queue) {
        SPDLOG_LOGGER_INFO(my_logger,"生产者线程1 - 启动写行情线程1");
        //pcapUtils.readNetworkIfaceLine("LINE_1", startTime, iniCfg, data_queue);
        //use_efvi(iniCfg);
        use_efvi2("LINE_1", iniCfg, data_queue);
    };
    //std::thread task(writeLambda, pcapUtils, my_nm_logger, iniCfg, startTime, data_queue1);
    std::thread task(writeLambda1, pcapUtils, my_nm_logger, iniCfg, startTime, &queueLine1);

    // 写行情2
    auto writeLambda2 = [](PcapUtils pcapUtils, std::shared_ptr<spdlog::logger> my_logger,
            IniReader* iniCfg, std::chrono::system_clock::time_point startTime, SafeQueue<MarketData>* data_queue) {
        SPDLOG_LOGGER_INFO(my_logger,"生产者线程2 - 启动写行情线程2");
        pcapUtils.readNetworkIfaceLine("LINE_2", startTime, iniCfg, data_queue);
    };
    //std::thread task3(writeLambda2, pcapUtils, my_nm_logger, iniCfg, startTime, &queueLine2);

    // 指标写入文件
    auto sampledLambda = [](PcapUtils pcapUtils, std::shared_ptr<spdlog::logger> my_logger, IniReader* iniCfg, std::chrono::system_clock::time_point startTime) {
        my_logger->info("采样统计线程 - 启动读行情线程");
        pcapUtils.saveFile(my_logger, iniCfg);
    };
    //std::thread task4(sampledLambda, pcapUtils, my_nm_logger, iniCfg, startTime);

    // 等待线程结束
    //task2.join();
    task.join();
    //task3.join();
    //task4.join();

}
